﻿namespace RPCenter.WindowsAPI
{
    using Microsoft.VisualBasic.CompilerServices; 
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Text;

    public class NativeFileSystem
    {
        public static void AssignDriveLetterToPath(char DriveLetter, string Path)
        {
            if (!ApiDefinitions.DefineDosDevice(0, Conversions.ToString(DriveLetter) + ":", Path))
            {
                throw new Win32Exception();
            }
        }

        public static void EmptyRecycleBin(bool RequireConfirmation, bool ShowProgress, bool PlaySound)
        {
            uint dwFlags = 0;
            if (!RequireConfirmation)
            {
                dwFlags |= (uint) 1L;
            }
            if (!ShowProgress)
            {
                dwFlags |= (uint) 2L;
            }
            if (!PlaySound)
            {
                dwFlags |= (uint) 4L;
            }
            ApiDefinitions.SHEmptyRecycleBin(IntPtr.Zero, null, dwFlags);
        }

        public static ulong GetFreeSpaceOnRemoteDisk(string Path)
        {
            if (string.IsNullOrEmpty(Path))
            {
                throw new ArgumentException("Path cannot be empty", "Path");
            }
            if (!Path.EndsWith(@"\"))
            {
                Path = Path + @"\";
            }
            ulong lpTotalNumberOfFreeBytes = 0L;
            ulong lpFreeBytesAvailable = 0L;
            ulong lpTotalNumberOfBytes = 0L;
            if (!ApiDefinitions.GetDiskFreeSpaceEx(Path, ref lpFreeBytesAvailable, ref lpTotalNumberOfBytes, ref lpTotalNumberOfFreeBytes))
            {
                throw new Win32Exception();
            }
            return (ulong) Math.Round((double) ((((double) lpTotalNumberOfFreeBytes) / 1024.0) / 1024.0));
        }

        public static ulong GetRecycleBinItemCount(char DriveLetter)
        {
            return QueryRecycleBin(DriveLetter).i64NumItems;
        }

        public static ulong GetRecycleBinSize(char DriveLetter)
        {
            return QueryRecycleBin(DriveLetter).i64Size;
        }

        public static List<SharedFolderInfo> GetSharedFolders()
        {
            return GetSharedFolders(null);
        }

        public static List<SharedFolderInfo> GetSharedFolders(string Server)
        {
            List<SharedFolderInfo> list;
            IntPtr zero = IntPtr.Zero;
            List<SharedFolderInfo> list2 = new List<SharedFolderInfo>();
            try
            {
                int num=0;
                int num2=0;
                IntPtr ptr2 = new IntPtr(2121);
                IntPtr ptr3 = ptr2;
                int num3 = ApiDefinitions.NetShareEnum(Server, 1, ref zero, -1, ref num, ref num2, ref ptr3);
                if (num3 != 0)
                {
                    throw new ApplicationException("NetShareEnum failed with error code " + Conversions.ToString(num3));
                }
                if (num > 0)
                {
                    int num5 = Marshal.SizeOf(typeof(ApiDefinitions.SHARE_INFO_1));
                    int num4 = zero.ToInt32();
                    int num7 = num - 1;
                    for (int i = 0; i <= num7; i++)
                    {
                        ptr3 = new IntPtr(num4);
                        ApiDefinitions.SHARE_INFO_1 share_info_ = (ApiDefinitions.SHARE_INFO_1) Marshal.PtrToStructure(ptr3, typeof(ApiDefinitions.SHARE_INFO_1));
                        if (((share_info_.shi1_type & ApiDefinitions.ShareType.STYPE_DISKTREE) == ApiDefinitions.ShareType.STYPE_DISKTREE) || ((share_info_.shi1_type & ApiDefinitions.ShareType.STYPE_SPECIAL) == ApiDefinitions.ShareType.STYPE_SPECIAL))
                        {
                            list2.Add(new SharedFolderInfo(share_info_.shi1_netname, share_info_.shi1_remark));
                        }
                        num4 += num5;
                    }
                }
                list = list2;
            }
            finally
            {
                if (!(zero == IntPtr.Zero))
                {
                    ApiDefinitions.NetApiBufferFree(zero);
                }
            }
            return list;
        }

        public static string GetUncPathFromNetworkDrive(char DriveLetter)
        {
            StringBuilder lpRemoteName = new StringBuilder(0xff);
            StringBuilder builder2 = lpRemoteName;
            int capacity = builder2.Capacity;
            ApiDefinitions.WNetGetConnection(Conversions.ToString(DriveLetter) + ":", lpRemoteName, ref capacity);
            builder2.Capacity = capacity;
            return lpRemoteName.ToString();
        }

        public static void MapNetworkDrive(string UncPath, char DriveLetter, bool Persistent, string ConnectionUsername ="", string ConnectionPassword = "")
        {
            if (string.IsNullOrEmpty(UncPath))
            {
                throw new ArgumentException("No UNC path specified", "UncPath");
            }
            ApiDefinitions.NETRESOURCE lpNetResource = new ApiDefinitions.NETRESOURCE {
                dwType = 1,
                lpLocalName = Conversions.ToString(DriveLetter) + ":",
                lpRemoteName = UncPath
            };
            uint dwFlags = 0;
            if (Persistent)
            {
                dwFlags = 1;
            }
            uint num2 = ApiDefinitions.WNetAddConnection2(ref lpNetResource, ConnectionPassword, ConnectionUsername, dwFlags);
            if (num2 != 0)
            {
                throw new Win32Exception((int) num2);
            }
        }

        private static ApiDefinitions.SHQUERYRBINFO QueryRecycleBin(char DriveLetter)
        {
            ApiDefinitions.SHQUERYRBINFO shqueryrbinfo;
            shqueryrbinfo = new ApiDefinitions.SHQUERYRBINFO {
                cbSize = (uint) Marshal.SizeOf(uint.MaxValue)
            };
            ApiDefinitions.SHQueryRecycleBin(Conversions.ToString(DriveLetter) + @":\", ref shqueryrbinfo);
            return shqueryrbinfo;
        }

        public static void RemoveAssignedDriveLetter(char DriveLetter, string Path)
        {
            if (!ApiDefinitions.DefineDosDevice(6, Conversions.ToString(DriveLetter) + ":", Path))
            {
                throw new Win32Exception();
            }
        }

        public static void RemoveNetworkDrive(char DriveLetter, bool Force)
        {
            uint num = ApiDefinitions.WNetCancelConnection(Conversions.ToString(DriveLetter) + ":", 1, Force);
            if (num != 0)
            {
                throw new Win32Exception((int) num);
            }
        }

        public static void ShareExistingFolder(string LocalPath, string ShareName, string Sharecomment)
        {
            ShareExistingFolder(LocalPath, ShareName, Sharecomment, string.Empty);
        }

        public static void ShareExistingFolder(string LocalPath, string ShareName, string ShareComment, List<SharePermissionEntry> SharePermissions)
        {
            ShareExistingFolder(LocalPath, ShareName, ShareComment, SharePermissions, string.Empty);
        }

        public static void ShareExistingFolder(string LocalPath, string ShareName, string Sharecomment, string ComputerName)
        {
            ApiDefinitions.SHARE_INFO_2 buf = new ApiDefinitions.SHARE_INFO_2 {
                shi2_netname = ShareName,
                shi2_type = 0,
                shi2_remark = Sharecomment,
                shi2_permissions = 0,
                shi2_max_uses = -1,
                shi2_current_uses = 0,
                shi2_path = LocalPath,
                shi2_passwd = null
            };
            uint num = 0;
            ApiDefinitions.NET_API_STATUS net_api_status = ApiDefinitions.NetShareAdd(ComputerName, 2, ref buf, out num);
            if (net_api_status != ApiDefinitions.NET_API_STATUS.NERR_SUCCESS)
            {
                throw new ApplicationException("Unable to share folder " + LocalPath + ". The following error was reported: " + net_api_status.ToString());
            }
        }

        public static void ShareExistingFolder(string LocalPath, string ShareName, string ShareComment, List<SharePermissionEntry> SharePermissions, string ComputerName)
        {
            IntPtr ptr = IntPtr.Zero;
            if ((string.IsNullOrEmpty(ShareName) || string.IsNullOrEmpty(LocalPath)) || ((SharePermissions == null) || (SharePermissions.Count == 0)))
            {
                throw new ArgumentException("Invalid argument specified - ShareName, LocalPath and SharePermissions arguments must not be empty");
            }
            ApiDefinitions.EXPLICIT_ACCESS[] explicit_accessArray = new ApiDefinitions.EXPLICIT_ACCESS[(SharePermissions.Count - 1) + 1];
            int num5 = explicit_accessArray.Length - 1;
            for (int i = 0; i <= num5; i++)
            {
                string str = string.Empty;
                if (!string.IsNullOrEmpty(SharePermissions[i].DomainName))
                {
                    str = SharePermissions[i].DomainName + @"\";
                }
                str = str + SharePermissions[i].UserOrGroupName;
                ApiDefinitions.TRUSTEE trustee = new ApiDefinitions.TRUSTEE {
                    MultipleTrusteeOperation = ApiDefinitions.MULTIPLE_TRUSTEE_OPERATION.NO_MULTIPLE_TRUSTEE,
                    pMultipleTrustee = 0,
                    TrusteeForm = ApiDefinitions.TRUSTEE_FORM.TRUSTEE_IS_NAME,
                    ptstrName = str,
                    TrusteeType = ApiDefinitions.TRUSTEE_TYPE.TRUSTEE_IS_UNKNOWN
                };
                ApiDefinitions.EXPLICIT_ACCESS[] explicit_accessArray2 = explicit_accessArray;
                int index = i;
                if (SharePermissions[i].AllowOrDeny)
                {
                    explicit_accessArray2[index].grfAccessMode = ApiDefinitions.ACCESS_MODE.GRANT_ACCESS;
                }
                else
                {
                    explicit_accessArray2[index].grfAccessMode = ApiDefinitions.ACCESS_MODE.DENY_ACCESS;
                }
                if (SharePermissions[i].Permission == SharePermission.Read)
                {
                    explicit_accessArray2[index].grfAccessPermissions = 0xa0020000;
                }
                else if (SharePermissions[i].Permission == SharePermission.FullControl)
                {
                    explicit_accessArray2[index].grfAccessPermissions = 0x10000000;
                }
                else if (SharePermissions[i].Permission == SharePermission.Change)
                {
                    explicit_accessArray2[index].grfAccessPermissions = 0x1301bf;
                }
                explicit_accessArray2[index].grfInheritance = 0;
                explicit_accessArray2[index].Trustee = trustee;
                uint num4 = ApiDefinitions.SetEntriesInAcl(1, ref explicit_accessArray[i], ptr, ref ptr);
                if (num4 == 0x534)
                {
                    throw new ApplicationException("The account " + str + " could not be mapped to a security identifier (SID). Check that the account name is correct and that the domain where the account is held is contactable. The share has not been created");
                }
                if (num4 != 0L)
                {
                    throw new ApplicationException("The account " + str + " could not be added to the ACL as the follow error was encountered: " + Conversions.ToString(num4) + ". The share has not been created");
                }
            }
            ApiDefinitions.SECURITY_DESCRIPTOR pSecurityDescriptor = new ApiDefinitions.SECURITY_DESCRIPTOR {
                Revision = 1
            };
            if (ApiDefinitions.InitializeSecurityDescriptor(ref pSecurityDescriptor, 1) == 0L)
            {
                throw new ApplicationException("An error was encountered during the call to the InitializeSecurityDescriptor API. The share has not been created.You may be able to get more information on the error by checking the Err.LastDllError property");
            }
            if (ApiDefinitions.SetSecurityDescriptorDacl(ref pSecurityDescriptor, true, ptr, false) == 0L)
            {
                throw new ApplicationException("An error was encountered during the call to the SetSecurityDescriptorDacl API. The share has not been created.You may be able to get more information on the error by checking the Err.LastDllError property");
            }
            if (ApiDefinitions.IsValidSecurityDescriptor(ref pSecurityDescriptor) == 0L)
            {
                throw new ApplicationException("No errors were reported from previous API calls but the security descriptor is not valid. The share has not been created.");
            }
            IntPtr ptr2 = Marshal.AllocCoTaskMem(Marshal.SizeOf(pSecurityDescriptor));
            try
            {
                Marshal.StructureToPtr(pSecurityDescriptor, ptr2, false);
                ApiDefinitions.SHARE_INFO_502 buf = new ApiDefinitions.SHARE_INFO_502 {
                    shi502_netname = ShareName,
                    shi502_type = 0,
                    shi502_remark = ShareComment,
                    shi502_permissions = 0,
                    shi502_max_uses = -1,
                    shi502_current_uses = 0,
                    shi502_path = LocalPath,
                    shi502_passwd = null,
                    shi502_reserved = 0,
                    shi502_security_descriptor = ptr2
                };
                int num7 = 0;
                ApiDefinitions.NET_API_STATUS net_api_status = ApiDefinitions.NetShareAdd(ComputerName, 0x1f6, ref buf, out num7);
                if (net_api_status != ApiDefinitions.NET_API_STATUS.NERR_SUCCESS)
                {
                    throw new ApplicationException("Unable to share folder " + LocalPath + ". The following error was reported: " + net_api_status.ToString());
                }
            }
            finally
            {
                Marshal.FreeCoTaskMem(ptr2);
            }
        }

        public class SharedFolderInfo
        {
            [CompilerGenerated]
            private string _Description;
            [CompilerGenerated]
            private string _Name;

            public SharedFolderInfo()
            {
            }

            public SharedFolderInfo(string ShareName, string ShareDescription)
            {
                this._Name = ShareName;
                this._Description = ShareDescription;
            }

            public string Description
            {
                get
                {
                    return this._Description;
                }
                set
                {
                    this._Description = value;
                }
            }

            public string Name
            {
                get
                {
                    return this._Name;
                }
                set
                {
                    this._Name = value;
                }
            }
        }

        public enum SharePermission
        {
            Change = 3,
            FullControl = 2,
            Read = 1
        }

        public class SharePermissionEntry
        {
            private bool _AllowOrDeny;
            private string _DomainName;
            private NativeFileSystem.SharePermission _Permission;
            private string _UserOrGroupName;

            public SharePermissionEntry()
            {
                this._DomainName = string.Empty;
                this._UserOrGroupName = string.Empty;
                this._AllowOrDeny = true;
            }

            public SharePermissionEntry(string Domain, string AccountName, NativeFileSystem.SharePermission DesiredPermission, bool AlloworDenyPermission)
            {
                this._DomainName = string.Empty;
                this._UserOrGroupName = string.Empty;
                this._AllowOrDeny = true;
                this.DomainName = Domain;
                this.UserOrGroupName = AccountName;
                this.Permission = DesiredPermission;
                this.AllowOrDeny = AlloworDenyPermission;
            }

            public bool AllowOrDeny
            {
                get
                {
                    return this._AllowOrDeny;
                }
                set
                {
                    this._AllowOrDeny = value;
                }
            }

            public string DomainName
            {
                get
                {
                    return this._DomainName;
                }
                set
                {
                    this._DomainName = value;
                }
            }

            public NativeFileSystem.SharePermission Permission
            {
                get
                {
                    return this._Permission;
                }
                set
                {
                    this._Permission = value;
                }
            }

            public string UserOrGroupName
            {
                get
                {
                    return this._UserOrGroupName;
                }
                set
                {
                    this._UserOrGroupName = value;
                }
            }
        }
    }
}

